/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.reporte.servlet;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import net.sf.jasperreports.engine.JRExporter;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRRtfExporter;
import net.sf.jasperreports.engine.export.JRTextExporter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.ooxml.JRDocxExporter;
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import net.sf.jasperreports.engine.util.JRLoader;
import org.reporte.accion.DatosReporteManejador;
import org.reporte.control.ProcesaDatosReporte;
import org.reporte.modelo.DatosReporte;
import org.reporte.modelo.Reporte;
import org.reporte.utils.JsfAyuda;

/**
 *
 * @author 43579648
 */
public class GeneraReporte extends HttpServlet {

    /** 
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        //Indicador que la salida sera un binario
        ServletOutputStream out = null;
        try {


            Long identificadorGenerador = new Long(request.getParameter("idReporteGenera"));
            DatosReporteManejador controlDatos = new DatosReporteManejador();
            ProcesaDatosReporte procesaDatos = new ProcesaDatosReporte(request.getLocale());


            try {
                //Obteniendo datos
                List<DatosReporte> datosReporte = controlDatos.obtenerDatosReportePorIdentificadorGenerador(identificadorGenerador);
                if (datosReporte == null || datosReporte.isEmpty()) {
                    System.out.println(JsfAyuda.getPropertyValue("reporteNoDatosGenera",request.getLocale()).replace("{0}", String.valueOf(identificadorGenerador)));
                    throw new ServletException(JsfAyuda.getPropertyValue("reporteNoDatosGenera",request.getLocale()).replace("{0}", String.valueOf(identificadorGenerador)));
                }
                
                //Procesando datos
                procesaDatos.cargaDatosParametros(datosReporte);
                
                //Validando reporte
                String reporteActivo=procesaDatos.obtenerValorParametroReportePermanente(
                        JsfAyuda.getPropertyValueFromConfigurationFile("reporteActivo")
                        ).toUpperCase();
                if(reporteActivo.toUpperCase().contains("NO") || reporteActivo.toUpperCase().contains("FALSE") || reporteActivo.contains("FALSO")){
                    throw new ServletException(JsfAyuda.getPropertyValue("reporteErrorNoActivo",request.getLocale()));
                }
                
                //Obteniendo y convirtiendo reporte desde la base de datos
                Reporte reporteEntidad = (Reporte) datosReporte.get(0).getIdReporte();
                ByteArrayInputStream reporteBinario = new ByteArrayInputStream(reporteEntidad.getFicheroReporte());
                JasperReport reporteJasper = null;

                //Verificando el tipo de fichero reporte almacenado
                if (reporteEntidad.getNombreFichero().contains("jasper")) {
                    reporteJasper = (JasperReport) JRLoader.loadObject(reporteBinario);   //Cargando el reporte
                } else if (reporteEntidad.getNombreFichero().contains("jrxml")) {
                    reporteJasper = JasperCompileManager.compileReport(reporteBinario); //Compilando y cargando el reporte
                } else {
                    System.out.println("El fichero almacenado en la base de datos no es un reporte");
                    throw new ServletException(JsfAyuda.getPropertyValue("reporteFicheroIncorrecto",request.getLocale())); //Interrupcion del proceso
                }

                //Evaluando si el reporte tiene conexion con la BD
                Connection conexion = null;
                String tieneConexionBD=procesaDatos.obtenerValorParametroReportePermanente(
                        JsfAyuda.getPropertyValueFromConfigurationFile("conexionBaseDatos")
                        ).toUpperCase();
                if(tieneConexionBD.contains("NO")||
                   tieneConexionBD.contains("FALSE")||
                   tieneConexionBD.contains("FALSO")){
                    System.out.println("Reporte no tiene conexion con Base de datos");
                }else{
                    System.out.println("Generando conexion con la base de datos");
                    //Generando conexion a partir de los parametros del reporte
                    conexion = obtenerConexionBaseDatos(procesaDatos);
                }
                

                //Generando los parametros que se pasaran al reporte
                Map parametros = new HashMap();
                //Evaluando si existen parametros dinamicos configurados al reporte
                if (procesaDatos.getListaParametrosReporteDinamica() != null || !procesaDatos.getListaParametrosReporteDinamica().isEmpty()) {
                    System.out.println("Obteniendo valores de los parametros dinamicos configurados al reporte");
                    for (DatosReporte d : procesaDatos.obtenerTodosDatosReporteDinamicos()) {
                        parametros.put(d.getNombre(), d.getValor());
                    }
                }


                JasperPrint jasperPrint = JasperFillManager.fillReport(reporteJasper, parametros, conexion);
                JRExporter exporter = null;

                //Obteniendo el tipo de reporte a generar
                String tipoReporte = procesaDatos.obtenerValorParametroReportePermanente(
                        JsfAyuda.getPropertyValueFromConfigurationFile("tipoReporte")
                        );
                //Cargando el tipo de reporte a generar
                if (tipoReporte.equalsIgnoreCase("txt")) {
                    response.setContentType("text/plain");
                    exporter = new JRTextExporter();
                } else if (tipoReporte.equalsIgnoreCase("xls")) {
                    response.setContentType("application/vnd.ms-excel");
                    exporter = new JRXlsExporter();
                } else if (tipoReporte.equalsIgnoreCase("pdf")) {
                    response.setContentType("application/pdf");
                    exporter = new JRPdfExporter();
                } else if (tipoReporte.equalsIgnoreCase("doc")) {
                    response.setContentType("application/msword");
                    exporter = new JRRtfExporter();
                } else if (tipoReporte.equalsIgnoreCase("xlsx")) {
                    response.setContentType("application/vnd.ms-excel");
                    exporter = new JRXlsxExporter();
                } else if (tipoReporte.equalsIgnoreCase("docx")) {
                    response.setContentType("application/msword");
                    exporter = new JRDocxExporter();
                } else if (tipoReporte.equalsIgnoreCase("csv")) {
                    response.setContentType("application/csv");
                    exporter = new JRCsvExporter();
                } else {
                    response.setContentType(procesaDatos.obtenerDatoReporteDesdeParametro(
                            JsfAyuda.getPropertyValueFromConfigurationFile(
                            JsfAyuda.getPropertyValueFromConfigurationFile("tipoContenido")
                            )
                            ).getValor());
                    exporter = (JRExporter) Class.forName(procesaDatos.obtenerDatoReporteDesdeParametro(
                            JsfAyuda.getPropertyValueFromConfigurationFile(
                            JsfAyuda.getPropertyValueFromConfigurationFile("importarClassJrexporter")
                            )
                            ).getValor()).newInstance();
                }
                
                //Lanzamiento del reporte
                out = response.getOutputStream();
                response.setHeader(JsfAyuda.getPropertyValue("paginaTituloSegundoNombre", request.getLocale()), reporteEntidad.getNombre());
                exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
                exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, out);
                exporter.exportReport();
                System.out.println("Reporte lanzado exitosamente");

            } catch (Exception ex) {
                System.out.println(JsfAyuda.getPropertyValue("reporteError",request.getLocale()) + ex.getMessage());
                ex.printStackTrace();
                throw new ServletException(JsfAyuda.getPropertyValue("reporteError",request.getLocale())+ " - "+ex.getMessage(), ex);
            }


        } finally {
            if (out != null) {
                out.close();
            }
        }
    }



    private Connection obtenerConexionBaseDatos(ProcesaDatosReporte procesaDatosReporte) throws Exception{

        boolean isJNDIConexion = false;
        try{
            isJNDIConexion = !procesaDatosReporte.obtenerValorParametroReportePermanente(JsfAyuda.getPropertyValueFromConfigurationFile("JNDIConexion")).equals("");
        }catch(Exception e){}

        if(isJNDIConexion){
            return obtenerConexionJNDI(procesaDatosReporte);
        }else{
            return obtenerConexionJDBC(procesaDatosReporte);
        }
    }

    /**
     * Genera la conexion a la base de datos segun los parametros configurados al reporte
     * @param ProcesaDatosReporte donde se obtienen los parametros permanentes configurados al reporte
     * @return Connection a la base de datos
     */
    private Connection obtenerConexionJDBC(ProcesaDatosReporte procesaDatosReporte) throws Exception {

        Connection connection = null;

        try {
            System.out.println("Cargando el driver de la conexion");
            Class.forName(procesaDatosReporte.obtenerValorParametroReportePermanente(
                    JsfAyuda.getPropertyValueFromConfigurationFile("driverConexion")
                    ));
            System.out.println("Driver cargador exitosamente");
            System.out.println("Generando la conexion");
            connection = DriverManager.getConnection(
                    procesaDatosReporte.obtenerValorParametroReportePermanente(
                    JsfAyuda.getPropertyValueFromConfigurationFile("urlConexion")
                    ),
                    procesaDatosReporte.obtenerValorParametroReportePermanente(
                    JsfAyuda.getPropertyValueFromConfigurationFile("usuarioConexion")
                    ),
                    procesaDatosReporte.obtenerValorParametroReportePermanente(
                    JsfAyuda.getPropertyValueFromConfigurationFile("contrasenaConexion")
                    ));
            System.out.println("Conexion generada exitosamente");
            return connection;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Error al cargar la conexion " + e.getMessage());
            throw new Exception(e);
        }

    }

    /**
     * Obtiene conexion a la base de datos segun la JNDI indicada en la configuracion del reporte
     * @param ProcesaDatosReporte donde se obtienen los parametros permanentes configurados al reporte
     * @return Connection a la base de datos
     */
    private Connection obtenerConexionJNDI(ProcesaDatosReporte procesaDatosReporte) throws Exception {

        Connection connection = null;

           DataSource ds = null;
             try {
               Context initCtx = new InitialContext();
               ds = (DataSource)initCtx.lookup(
                       procesaDatosReporte.obtenerValorParametroReportePermanente(JsfAyuda.getPropertyValueFromConfigurationFile("JNDIConexion"))
                       );
               connection = ds.getConnection();
               return connection;
             }catch (Exception e){
                e.printStackTrace();
                System.out.println("Error al cargar la conexion " + e.getMessage());
                throw new Exception(e);
             }
        }



    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** 
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
